package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

// 日志文件句柄，全局变量以便复用
var logFile *os.File

func init() {
	// 初始化时打开日志文件
	var err error
	logFile, err = os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		panic(fmt.Sprintf("Failed to open log file: %v", err))
	}
}

// loggingHandler 作为中间件，包装实际处理器
func loggingHandler(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		startTime := time.Now()

		// 创建自定义响应写入器，用于捕获状态码
		lrw := &loggingResponseWriter{ResponseWriter: w, statusCode: http.StatusOK}

		// 记录请求信息
		logRequest(r, startTime)

		// 传递请求给下一个处理器
		next.ServeHTTP(lrw, r)

		// 记录响应信息
		logResponse(r, lrw.statusCode, time.Since(startTime))
	})
}

// 自定义响应写入器，用于捕获状态码
type loggingResponseWriter struct {
	http.ResponseWriter
	statusCode int
}

func (lrw *loggingResponseWriter) WriteHeader(code int) {
	lrw.statusCode = code
	lrw.ResponseWriter.WriteHeader(code)
}

func logRequest(r *http.Request, startTime time.Time) {
	// 读取请求体（限制大小为 1MB，避免内存溢出）
	var requestBody string
	if r.Body != nil {
		body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20)) // 1MB
		if err == nil {
			requestBody = string(body)
			// 恢复请求体，以便后续处理器可以继续读取
			r.Body = io.NopCloser(io.LimitReader(r.Body, 1<<20))
		}
	}

	logLine := fmt.Sprintf(
		"[%s] [REQUEST] %s %s %s %s\n",
		startTime.Format("2006-01-02 15:04:05"),
		r.Method,
		r.URL.Path,
		r.Proto,
		truncateString(requestBody, 500), // 截断过长的请求体
	)

	writeLog(logLine)
}

func logResponse(r *http.Request, statusCode int, duration time.Duration) {
	logLine := fmt.Sprintf(
		"[%s] [RESPONSE] %s %s %d %s %s\n",
		time.Now().Format("2006-01-02 15:04:05"),
		r.Method,
		r.URL.Path,
		statusCode,
		duration,
		http.StatusText(statusCode),
	)

	writeLog(logLine)
}

func writeLog(logLine string) {
	if _, err := logFile.WriteString(logLine); err != nil {
		fmt.Printf("Error writing to log file: %v\n", err)
	}
}

func truncateString(s string, maxLen int) string {
	if len(s) <= maxLen {
		return s
	}
	return s[:maxLen] + "..."
}

func main() {
	// 创建默认路由复用器
	mux := http.NewServeMux()

	// 注册默认处理器（所有未匹配的路径都会到这里）
	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprintf(w, "404 Not Found: %s", r.URL.Path)
	})

	// 注册其他需要的路由（这些路由也会经过日志处理）
	mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	})

	// 将日志中间件应用到所有路由
	// 这里用 loggingHandler 包装 mux，实现全链路日志
	http.Handle("/", loggingHandler(mux))

	fmt.Println("Server started on :8080")
	http.ListenAndServe(":8080", nil)
}
